use serde::Deserialize;
use sqlx::Executor;

use crate::error::SqlxErr;

use super::{get_pool, replenish};

const CREATE_SQL: &'static str = r#"
CREATE TABLE IF NOT EXISTS tb_cargo_state (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    device_id INTEGER NOT NULL, 
    replenish_id INTEGER NOT NULL, 
    col INTEGER NOT NULL, 
    row INTEGER NOT NULL, 
    count INTEGER NOT NULL,
    UNIQUE (device_id, replenish_id, col, row),
    FOREIGN KEY (device_id) REFERENCES tb_device(id) ON DELETE CASCADE
)
"#;

pub async fn init() -> Result<(), SqlxErr> {
    get_pool().execute(CREATE_SQL).await?;
    Ok(())
}

#[derive(Debug, Deserialize)]
pub struct CargoInfo {
    pub col: u8,
    pub row: u8,
    pub count: u8,
}

#[derive(Debug, Deserialize)]
pub struct CargoState {
    pub replenish_timestamp: u64,
    pub infos: Box<[CargoInfo]>,
}

pub async fn cargo_replenish(device_id: i64, state: &CargoState) -> Result<(), SqlxErr> {
    let mut tx = get_pool().begin().await?;
    if replenish::is_exists(&mut *tx, device_id, state.replenish_timestamp)
        .await?
        .is_none()
    {
        let replenish_id =
            replenish::create(&mut *tx, device_id, state.replenish_timestamp).await?;
        for info in state.infos.iter() {
            sqlx::query(r#"
                INSERT INTO tb_cargo_state (device_id, replenish_id, col, row, count) VALUES (?, ?, ?, ?, ?)
            "#)
            .bind(device_id)
            .bind(replenish_id)
            .bind(info.col)
            .bind(info.row)
            .bind(info.count)
            .execute(&mut *tx)
            .await?;
        }
    }
    tx.commit().await?;
    Ok(())
}
